﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Pyramid.Hardware.Interop
{
    public class OutputBus
    {
        private readonly IEnumerable<ILine> inputBus;

        public OutputBus(IEnumerable<ILine> inputBus)
        {
            this.inputBus = inputBus;
        }

        public ITernary Value
        {
            get
            {
                return new TernaryOutput(this.inputBus);
            }
        }

        private struct TernaryOutput
            : ITernary
        {
            private readonly IEnumerable<ILine> inputBus;

            public TernaryOutput(IEnumerable<ILine> inputBus)
            {
                this.inputBus = inputBus.ToArray();
            }

            public int TritSize
            {
                get
                {
                    return this.inputBus.Count();
                }
            }

            public Trivalent[] ToTritArray()
            {
                return this.inputBus.Select(line => line.Signal).ToArray();
            }

            public Tryte ToTryte()
            {
                Tryte result = 0;

                short tritValue = 1;

                int lineCount = Math.Min(Tryte.TritsPerTryte, this.TritSize);

                for (int lineIndex = 0; lineIndex < lineCount; lineIndex++)
                {
                    result += (Tryte)((short)this.inputBus.ElementAt(lineIndex).Signal * tritValue);

                    tritValue *= 3;
                }

                return result;
            }

            public Int27 ToInt27()
            {
                Int27 result = 0;

                long tritValue = 1;

                int lineCount = Math.Min(Int27.TritsPerInt27, this.TritSize);

                for (int lineIndex = 0; lineIndex < lineCount; lineIndex++)
                {
                    result += (Int27)((long)this.inputBus.ElementAt(lineIndex).Signal * tritValue);

                    tritValue *= 3;
                }

                return result;
            }
        }
    }
}
